package dst.ass3.aop.logging;

import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class LoggingAspect {

	//http://docs.spring.io/spring/docs/2.0.x/reference/aop.html
	
	//use of the Invisible annotation
    @Pointcut("execution(* dst.ass3.aop.IPluginExecutable.execute(..)) && !@annotation(Invisible)")
    void anyCall() { /*do nothing <-- Invisible*/ }

    @Before("anyCall()")
    public void beforeAnyCall(JoinPoint thisJoinPoint) {
        logExecution(thisJoinPoint, "Before");
    }

    @After("anyCall()")
    public void afterAnyCall(JoinPoint thisJoinPoint) {
        logExecution(thisJoinPoint, "After");
    }

    /**
     * log the Exception that occur Before and After anyCall
     */
    private void logExecution(JoinPoint thisJoinPoint, String prefix) {
        String loggingMessage = String.format("Prefix: %s Target: %s \n", prefix, thisJoinPoint.getTarget());

        Logger logger = searchLoggerInClass(thisJoinPoint.getTarget());
        if(logger==null) {
            System.out.println(loggingMessage);
        }
        else {
            logger.setLevel(Level.INFO);	//of logger was found set the Log Level
            logger.info(loggingMessage);	//and log
        } 
    }

    /**
     * Try tp find 
     */
    private Logger searchLoggerInClass(Object loggingTarget) {
    	Logger foundLogger=null;
        Class<?> loggingTargetClass = loggingTarget.getClass();
        
        for (Field field : loggingTargetClass.getDeclaredFields()) { //search all fields in object to find logger object
            if (Logger.class.isAssignableFrom(field.getType())) {  //is it a Logger type or superType
	            boolean accessibleState = field.isAccessible();
	            
	            try {
	                field.setAccessible(true);  //to be sure to set the object
	                foundLogger= (Logger)(field.get(loggingTarget));
	                break;
	            } catch (IllegalArgumentException e) {
	                e.printStackTrace();
	            } catch (IllegalAccessException e) {
	                e.printStackTrace();
	            } finally {
	                field.setAccessible(accessibleState);
	            }
            }
        }
        return foundLogger;
    }

}